/*******************************************************************************
 * Venice Noise Android Application
 * Copyright (C) 2011  Worcester Polytechnic Institute, Wesley Ripley
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; version 2
 * of the License
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 * 
 * If you plan to use or modify any of this code please contact Fabio Carrera (carrera.fabio@gmail.com)
 * Also please attribute any code used in the final product to the developers. 
 * 
 * Author: Wesley Ripley (wripley@wpi.edu) 
 *******************************************************************************/
package org.venicenoise.app.location;

import android.location.Location;

/**
 * A LocationPicker that picks the location that is the best possible
 * location estimate for use in tagging user data
 * @author Wesley Ripley
 * @version 12/16/2011
 */
public class TagEstimateLocationPicker implements LocationPicker {

	private static final int SIGNIFICANTLY_DIFFERENT_TIME_DELTA = 1000 * 60 * 2;
	private static final int SIGNIFICANTLY_LESS_ACCURATE_DELTA = 200;
	
	private final int newerTimeDelta;
	private final int olderTimeDelta;
	private final int lessAccurateDelta;
	
	/**
	 * Constructor for a TagEstimateLocationPicker
	 */
	public TagEstimateLocationPicker()
	{
		this(SIGNIFICANTLY_DIFFERENT_TIME_DELTA,SIGNIFICANTLY_DIFFERENT_TIME_DELTA,SIGNIFICANTLY_LESS_ACCURATE_DELTA);
	}
	
	/**
	 * Constructor for TagEstimateLocationPicker
	 * @param newerTimeDelta
	 * 		the length of time between locations for a location to be considered significantly newer
	 * @param olderTimeDelta
	 * 		the length of time between locations for a location to be considered significantly older
	 * @param lessAccurateDelta
	 * 		the difference in accuracy for a location to be considered significantly less accurate
	 */
	public TagEstimateLocationPicker(int newerTimeDelta, int olderTimeDelta, int lessAccurateDelta)
	{
		this.newerTimeDelta = newerTimeDelta;
		this.olderTimeDelta = olderTimeDelta;
		this.lessAccurateDelta = lessAccurateDelta;
	}
	
	//adapted from http://developer.android.com/guide/topics/location/obtaining-user-location.html#BestPerformance
	public boolean isBetterLocation(Location location, Location currentLocation) {
		if (currentLocation == null) {
			// A new location is always better than no location
			return true;
		}
		else if (location == null)
		{
			return false;
		}

		// Check whether the new location fix is newer or older
		long timeDelta = location.getTime() - currentLocation.getTime();
		boolean isSignificantlyNewer = timeDelta > newerTimeDelta;
		boolean isSignificantlyOlder = timeDelta < -olderTimeDelta;
		boolean isNewer = timeDelta > 0;

		// If it's been more than two minutes since the current location, use the new location
		// because the user has likely moved
		if (isSignificantlyNewer) {
			return true;
			// If the new location is more than two minutes older, it must be worse
		} else if (isSignificantlyOlder) {
			return false;
		}

		// Check whether the new location fix is more or less accurate
		int accuracyDelta = (int) (location.getAccuracy() - currentLocation.getAccuracy());
		boolean isLessAccurate = accuracyDelta > 0;
		boolean isMoreAccurate = accuracyDelta < 0;
		boolean isSignificantlyLessAccurate = accuracyDelta > lessAccurateDelta;

		// Check if the old and new location are from the same provider
		boolean isFromSameProvider = isSameProvider(location.getProvider(),
				currentLocation.getProvider());

		// Determine location quality using a combination of timeliness and accuracy
		if (isMoreAccurate) {
			return true;
		} else if (isNewer && !isLessAccurate) {
			return true;
		} else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
			return true;
		}
		return false;
	}
	
	/**
	 * Checks whether two providers are the same 
	 */
	private boolean isSameProvider(String provider1, String provider2) {
		if (provider1 == null) {
			return provider2 == null;
		}
		return provider1.equals(provider2);
	}

}
